﻿/*********************************************************************************
 *Author:         OnClick
 *Version:        0.0.2.155
 *UnityVersion:   2019.4.16f1
 *Date:           2021-07-28
 *Description:    IFramework
 *History:        2018.11--
*********************************************************************************/
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
namespace IFramework.Utility.AtlasBuilder
{
    [CustomEditor(typeof(Atlas))]
    class AtlasEditor : Editor
    {
        class AtlasInitializer : EditorEnv.FileInitializer
        {
            private static string atlasSourcePath { get { return EditorEnv.scriptablePath.CombinePath("Atlas.asset"); } }

            protected override List<string> directorys { get; }
            protected override List<string> files
            {
                get
                {
                    return new List<string>
                    {
                        atlasSourcePath
                    };
                }
            }
            protected override bool CreateFile(int index, string path)
            {
                if (!ExistFile(path))
                {
                    string tmpPath = Application.dataPath.CombinePath("Atlas.asset").ToAssetsPath();
                    EditorTools.ScriptableObjectTool.Create<Atlas>(tmpPath);
                    File.Move(tmpPath, path);
                }
                return true;
            }
            [MenuItem("Assets/IFramework/Create/Atlas")]
            private static void CreateNew()
            {
                string path = "Assets";
                if (Selection.activeObject)
                {
                    var tmp = AssetDatabase.GetAssetPath(Selection.activeObject);
                    path = tmp.IsDirectory() ? tmp : tmp.GetDirPath();
                }
                CopyAsset.Copy(path.CombinePath("New Atlas.asset"), atlasSourcePath);
            }
        }


        private Atlas _atlas { get { return this.target.As<Atlas>(); } }
        [System.NonSerialized] private Editor _texEditor;
        public override bool HasPreviewGUI()
        {
            return _atlas.texture != null;
        }
        private void BuildPreviewEditor()
        {
            _texEditor = Editor.CreateEditor(_atlas.texture);
            _previews.Clear();
            _watchIndex = 0;
        }
        public override void DrawPreview(Rect previewArea)
        {
            if (_texEditor == null)
            {
                BuildPreviewEditor();
            }
            _texEditor.DrawPreview(previewArea);
        }
        public override void OnInspectorGUI()
        {
            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(this.serializedObject.FindProperty("padding"));
            EditorGUILayout.PropertyField(this.serializedObject.FindProperty("maximumAtlasSize"));
            EditorGUILayout.PropertyField(this.serializedObject.FindProperty("compress"));
            EditorGUILayout.PropertyField(this.serializedObject.FindProperty("sources"), true);

            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }
            if (GUILayout.Button("Build"))
            {
                if (_atlas.sources.Length <= 0) return;
                List<string> paths = new List<string>();
                List<Sprite> sprites = new List<Sprite>();
                List<Texture2D> newTexs = new List<Texture2D>();

                for (int i = 0; i < _atlas.sources.Length; i++)
                {
                    string txpath = AssetDatabase.GetAssetPath(_atlas.sources[i]);
                    if (!string.IsNullOrEmpty(txpath) && !paths.Contains(txpath))
                    {
                        paths.Add(txpath);
                    }
                }
                for (int i = 0; i < paths.Count; i++)
                {
                    string txpath = paths[i];
                    Object[] newSprites = AssetDatabase.LoadAllAssetsAtPath(txpath);
                    for (int j = 0; j < newSprites.Length; j++)
                    {
                        if ((newSprites[j] as Sprite) != null)
                            sprites.Add(newSprites[j] as Sprite);
                    }
                }
                for (int i = 0; i < sprites.Count; i++)
                {
                    Rect t_Rect = sprites[i].rect;
                    Texture2D t_SourceTex = sprites[i].texture;
                    string pathStr = AssetDatabase.GetAssetPath(sprites[i].texture);
                    // 开启源Spirte的可读
                    TextureImporter t_Importer = AssetImporter.GetAtPath(pathStr) as TextureImporter;
                    t_Importer.isReadable = true;
                    t_Importer.SaveAndReimport();
                    AssetDatabase.ImportAsset(pathStr);
                    // 裁剪出新的Texture
                    Color[] t_Colors = t_SourceTex.GetPixels((int)t_Rect.x, (int)t_Rect.y, (int)t_Rect.width, (int)t_Rect.height);
                    newTexs.Add(new Texture2D((int)t_Rect.width, (int)t_Rect.height));
                    newTexs[i].SetPixels(t_Colors);
                }


                var tex = new Texture2D(1, 1);
                var rects = tex.PackTextures(newTexs.ToArray(), _atlas.padding, _atlas.maximumAtlasSize, false);
                if (rects == null) return;
                if (_atlas.compress)
                {
                    tex.Compress(true);
                }
                tex.Apply();
                tex = tex.CreateReadableTexture();
                string path = AssetDatabase.GetAssetPath(_atlas);
                path = path.GetDirPath().CombinePath($"{path.GetFileNameWithoutExtend()}.png");
                File.WriteAllBytes(path, tex.EncodeToPNG());
                AssetDatabase.ImportAsset(path);
                AssetDatabase.Refresh();
                tex = AssetDatabase.LoadAssetAtPath<Texture2D>(path);

                SpriteMetaData[] atlasSheets = new SpriteMetaData[rects.Length];
                // 设置Atlas的sprite
                for (int i = 0; i < atlasSheets.Length; i++)
                {
                    SpriteMetaData t_Meta = new SpriteMetaData();
                    t_Meta.name = sprites[i].name;
                    t_Meta.rect = rects[i];
                    t_Meta.rect.Set(
                        t_Meta.rect.x * tex.width,
                        t_Meta.rect.y * tex.height,
                         t_Meta.rect.width * tex.width,
                         t_Meta.rect.height * tex.height
                    );
                    t_Meta.alignment = 9;
                    Rect t_Rect = sprites[i].rect;
                    t_Meta.pivot = new Vector2(sprites[i].pivot.x / t_Rect.width, sprites[i].pivot.y / t_Rect.height);
                    atlasSheets[i] = t_Meta;
                }
                TextureImporter atlas_Importer = AssetImporter.GetAtPath(path) as TextureImporter;
                atlas_Importer.textureType = TextureImporterType.Sprite;
                atlas_Importer.spriteImportMode = SpriteImportMode.Multiple;
                //imp.textureCompression = TextureImporterCompression.Uncompressed;
                atlas_Importer.mipmapEnabled = false;
                atlas_Importer.spritesheet = atlasSheets;
                atlas_Importer.isReadable = true;
                atlas_Importer.SaveAndReimport();

                AssetDatabase.ImportAsset(path);
                AssetDatabase.Refresh();

                _atlas.data = new Atlas.AtlasData[rects.Length];
                for (int i = 0; i < rects.Length; i++)
                {
                    var rect = rects[i];
                    float xstart = tex.width * rect.x;
                    float ystart = rect.y * tex.height;
                    float width = rect.width * tex.width;
                    float height = rect.height * tex.height;
                    _atlas.data[i] = new Atlas.AtlasData()
                    {
                        rect = new Rect(xstart, ystart, width, height),
                        name = sprites[i].name,
                        pivot = sprites[i].pivot,
                        pixelsPerUnit = sprites[i].pixelsPerUnit
                    };
                }
                _atlas.texture = tex;
                BuildPreviewEditor();
                EditorUtility.SetDirty(_atlas);
                AssetDatabase.Refresh();
            }
			if (_atlas.texture!=null)
			{
                _watchIndex = EditorGUILayout.IntSlider("Index", _watchIndex, 0, _atlas.data.Length - 1);
				Atlas.AtlasData _data = _atlas.data[_watchIndex];
                Sprite _sprite = _atlas.GetSprite(_watchIndex);

				if (!_previews.ContainsKey(_watchIndex))
				{
                    _previews[_watchIndex] = Editor.CreateEditor(_sprite);
				}
                var rect = EditorGUILayout.GetControlRect( GUILayout.Height(_sprite.rect.height));
                _previews[_watchIndex].DrawPreview(rect);
                _previews[_watchIndex].OnInspectorGUI();
                rect.yMin = rect.yMax;
                rect.yMax = rect.yMin + 17;
                rect.xMin = rect.xMax - 50;
				if (GUI.Button(rect, "Copy"))
				{
                    GUIUtility.systemCopyBuffer = _data.name;
                }
            }
        }

        private int _watchIndex = 0;
        private Dictionary<int, Editor> _previews = new Dictionary<int, Editor>();
    }
}
